package shayu.order.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import io.renren.common.exception.NoStockException;
import io.renren.common.mq.OrderTo;
import io.renren.common.to.mq.SeckillOrderTo;
import io.renren.common.utils.PageUtils;
import io.renren.common.utils.Query;
import io.renren.common.utils.R;
import io.renren.common.vo.MemberResponseVo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import shayu.order.constant.OrderConstant;
import shayu.order.dao.OrderDao;
import shayu.order.entity.OrderEntity;
import shayu.order.entity.OrderItemEntity;
import shayu.order.entity.PaymentInfoEntity;
import shayu.order.enume.OrderStatusEnum;
import shayu.order.feign.CartFeign;
import shayu.order.feign.MemberFeign;
import shayu.order.feign.ProductFeign;
import shayu.order.feign.WmsFeign;
import shayu.order.interceptor.LoginUserInterceptor;
import shayu.order.service.OrderItemService;
import shayu.order.service.OrderService;
import shayu.order.service.PaymentInfoService;
import shayu.order.to.OrderCreateTo;
import shayu.order.vo.*;

import javax.xml.crypto.Data;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    private ThreadLocal<OrderSubmitVo> confirmVoThreadLocal = new ThreadLocal<>();

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private CartFeign cartFeign;

    @Autowired
    private WmsFeign wmsFeign;

    @Autowired
    private MemberFeign memberFeign;

    @Autowired
    private ProductFeign productFeign;

    @Autowired
    private ThreadPoolExecutor executor;

    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    private PaymentInfoService paymentInfoService;

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private RabbitTemplate rabbitTemplate;



    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {

        MemberResponseVo memberResponseVo = LoginUserInterceptor.login_user.get();
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();

        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 1. 远程查询所有的收获地址列表
        CompletableFuture<Void> addrFuture = CompletableFuture.runAsync(() -> {
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberAddressVo> address = memberFeign.getAddress(memberResponseVo.getId());
            orderConfirmVo.setAddress(address);
        }, executor);

        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
            // 2. 远程查询购物车所有选中的购物项
            // 每一个线程都来共享之前请求的数据
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<OrderItemVo> currentUserItem = cartFeign.getCurrentUserItem();
            orderConfirmVo.setItems(currentUserItem);
            //  feign在远程调用之前要构造请求，调用很多拦截器
        }, executor).thenRunAsync(() -> {
            List<OrderItemVo> items = orderConfirmVo.getItems();

            List<Long> collect = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
            R skusHasStock = wmsFeign.getSkusHasStock(collect);
            List<SkuStockVo> data = skusHasStock.getData("data",new TypeReference<List<SkuStockVo>>() {
            });
            if (data != null&& data.size() > 0) {
                Map<Boolean, Long> map = data.stream().collect(Collectors.toMap(SkuStockVo::getHasStock, SkuStockVo::getSkuId));
                orderConfirmVo.setStock(map);
            }
        }, executor);

        // 3. 查询用户积分
        Integer integration = memberResponseVo.getIntegration();
        orderConfirmVo.setIntegration(integration);

        // 4. 其他数据计算

        // 5. 防重令牌
        String token = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(OrderConstant.USER_ORDE_TOKEN_PREFOX + memberResponseVo.getId().toString(), token, 30, TimeUnit.MINUTES);
        orderConfirmVo.setOrderToken(token);
        CompletableFuture.allOf(addrFuture, cartFuture).get();

        return orderConfirmVo;

    }

    // 下单服务
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SumbitOrderResponseVo sumbitOrder(OrderSubmitVo vo) {

        confirmVoThreadLocal.set(vo);

        SumbitOrderResponseVo sumbitOrderResponseVo = new SumbitOrderResponseVo();

        // 获取用户信息
        MemberResponseVo memberResponseVo = LoginUserInterceptor.login_user.get();

        // 1. 验证令牌
        String scribt = "f redis. call (\"get\",KEYS [ 1 ]) == ARGV [ 1] then return redis. call (\"del\",KEYS [ 1 ]) else return 0 end ";
        String orderToken = vo.getOrderToken();

        // 验证是否合法[必须保证原子性]
        Long result = (Long) redisTemplate.execute(new DefaultRedisScript<Long>(scribt, Long.class),
                Arrays.asList(OrderConstant.USER_ORDE_TOKEN_PREFOX + memberResponseVo.getId()), orderToken);
        if (result == 0L) {
            // 令牌验证失败
            sumbitOrderResponseVo.setCode(1);
            return sumbitOrderResponseVo;
        } else {
            // 令牌验证成功
            // 下单 去创建订单 验令牌 验价格 锁库存
            // 1. 创建订单，订单项等信息
            OrderCreateTo order = createOrder();

            // 2.验价格
            BigDecimal payAmount = order.getOrder().getPayAmount();
            BigDecimal payPrice = vo.getPayPrice();
            if (Math.abs(payAmount.subtract(payPrice).doubleValue()) < 0.01) {
                // 金额对比
                // 保存订单
                saveorder(order);
                // 4.锁定库存。只要有异常回滚订单数据
                // 订单号，所有订单项(skuId,skuName,num)
                WareSkuLockVo lockVo = new WareSkuLockVo();
                lockVo.setOrderSn(order.getOrder().getOrderSn());

                List<OrderItemVo> locks = order.getOrderItem().stream().map(item -> {
                    OrderItemVo orderItemVo = new OrderItemVo();
                    orderItemVo.setSkuId(item.getSkuId());
                    orderItemVo.setCount(item.getSkuQuantity());
                    orderItemVo.setTitle(item.getSkuName());
                    return orderItemVo;
                }).collect(Collectors.toList());
                lockVo.setLocks(locks);

                R r = wmsFeign.orderLockStock(lockVo);
                if (r.getCode() == 0) {
                    // 锁成功了
                    sumbitOrderResponseVo.setOrder(order.getOrder());
                    // 订单创建成功，发送消息给MQ
                    rabbitTemplate.convertAndSend("order-event-exchange","order.create.order",order.getOrder());

                    return sumbitOrderResponseVo;
                } else {
                    // 锁失败了
                    String msg = (String) r.get("msg");
                    throw new NoStockException(msg);
                }
            } else {
                sumbitOrderResponseVo.setCode(2);
                return sumbitOrderResponseVo;
            }
        }
    }

    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {
        return this.getOne(new QueryWrapper<OrderEntity>().eq("OrderSn", orderSn));

    }

    // 关闭订单
    @Override
    public void closeOrder(OrderEntity entity) {

        //关闭订单之前先查询一下数据库，判断此订单状态是否已支付
        OrderEntity orderInfo = this.getOne(new QueryWrapper<OrderEntity>().
                eq("order_sn",entity.getOrderSn()));

        if (orderInfo.getStatus().equals(OrderStatusEnum.CREATE_MEW.getCode())) {
            //代付款状态进行关单
            OrderEntity orderUpdate = new OrderEntity();
            orderUpdate.setId(orderInfo.getId());
            orderUpdate.setStatus(OrderStatusEnum.CANCLED.getCode());
            this.updateById(orderUpdate);

            // 发送消息给MQ
            OrderTo orderTo = new OrderTo();
            BeanUtils.copyProperties(orderInfo, orderTo);

            try {
                //TODO 确保每个消息发送成功，给每个消息做好日志记录，(给数据库保存每一个详细信息)保存每个消息的详细信息
                rabbitTemplate.convertAndSend("order-event-exchange", "order.release.other", orderTo);
            } catch (Exception e) {
                //TODO 定期扫描数据库，重新发送失败的消息
            }
        }
    }

    // 获取订单支付情况
    @Override
    public PayVo getOrderPay(String orderSn) {
        PayVo payVo = new PayVo();
        OrderEntity order = this.getOrderByOrderSn(orderSn);

        BigDecimal bigDecimal = order.getPayAmount().setScale(2, BigDecimal.ROUND_UP);
        payVo.setTotal_amount(bigDecimal.toString());
        payVo.setOut_trade_no(order.getOrderSn());

        //查询订单项的数据
        List<OrderItemEntity> order_sn = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", orderSn));
        OrderItemEntity entity = order_sn.get(0);

        payVo.setSubject(entity.getSkuName());
        payVo.setBody(entity.getSkuAttrsVals());
        return payVo;
    }

    @Override
    public PageUtils queryPageWithItem(Map<String, Object> params) {
        MemberResponseVo responseVo = LoginUserInterceptor.login_user.get();

        IPage<OrderEntity> page = this.page(new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>().eq("member_id", responseVo.getId()).orderByDesc("create_time")
        );
        List<OrderEntity> order_sn = page.getRecords().stream().map(item -> {
            List<OrderItemEntity> itemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>().eq("order_sn", item.getOrderSn()));
            item.setItemEntity(itemEntities);
            return item;
        }).collect(Collectors.toList());

        page.setRecords(order_sn);

        return new PageUtils(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String handlePayResult(PayAsyncVo vo) {
        // 1.  保存交易流水
        PaymentInfoEntity infoEntity = new PaymentInfoEntity();
        infoEntity.setAlipayTradeNo(vo.getTrade_no());
        infoEntity.setOrderSn(vo.getOut_trade_no());
        infoEntity.setPaymentStatus(vo.getTrade_status());
        infoEntity.setCallbackTime(vo.getNotify_time());

        paymentInfoService.save(infoEntity);

        // 2. 修改订单的状态信息
        if (vo.getTrade_status().equals("TRADE_SUCCES") || vo.getTrade_status().equals("TRADE_FINISHED")) {
            String outTradeNo = vo.getOut_trade_no();
            // 支付成功状态
            orderDao.updateOrderStatus(outTradeNo,OrderStatusEnum.PAYED.getCode());
        }

        return "success";
    }

    @Override
    public void createSeckillOrder(SeckillOrderTo seckillOrderTo) {
        // 保存订单信息
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(seckillOrderTo.getOrderSn());
        orderEntity.setMemberId(seckillOrderTo.getMemberId());
        orderEntity.setCreateTime(new Date());
        BigDecimal totalPrice = seckillOrderTo.getSeckillPrice().multiply(BigDecimal.valueOf(seckillOrderTo.getNum()));
        orderEntity.setPayAmount(totalPrice);
        orderEntity.setStatus(OrderStatusEnum.CREATE_MEW.getCode());

//        BigDecimal multiplicand = BigDecimal.valueOf(seckillOrderTo.getNum());
//        seckillOrderTo.getSeckillPrice().multiply(multiplicand);

        // 保存
        this.save(orderEntity);

        // 保存订单项信息
        OrderItemEntity orderItemEntity = new OrderItemEntity();

        orderItemEntity.setOrderSn(seckillOrderTo.getOrderSn());
        orderItemEntity.setRealAmount(totalPrice);

        orderItemEntity.setSkuQuantity(seckillOrderTo.getNum());

        //保存商品的spu信息
        R spuInfo = productFeign.getSpuInfoByskuId(seckillOrderTo.getSkuId());
        SpuInfoVo spuInfoData = spuInfo.getData("data", new TypeReference<SpuInfoVo>() {
        });
        orderItemEntity.setSpuId(spuInfoData.getSpuId());
        orderItemEntity.setSpuName(spuInfoData.getSpuName());
        orderItemEntity.setSpuBrand(spuInfoData.getBrandName()  );
        orderItemEntity.setCategoryId(spuInfoData.getCatalogId());

        orderItemService.save(orderItemEntity);
    }


    // 构建订单
    private OrderEntity buildOrder(String orderSn) {
        MemberResponseVo respVo = LoginUserInterceptor.login_user.get();
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(orderSn);
        orderEntity.setMemberId(respVo.getId());

        OrderSubmitVo submitVo = confirmVoThreadLocal.get();

        R fare = wmsFeign.getFare(submitVo.getAddrId());
        // 获取收货地址信息
        FareVo fareData = fare.getData(new TypeReference<FareVo>() {
        });

        // 设置运费信息
        orderEntity.setFreightAmount(fareData.getFare());
        // 设置收件人信息
        MemberAddressVo address = fareData.getAddress();
        orderEntity.setReceiverCity(address.getCity());
        orderEntity.setReceiverDetailAddress(address.getDetailAddress());
        orderEntity.setReceiverName(address.getDetailAddress());
        orderEntity.setReceiverPhone(address.getPhone());
        orderEntity.setReceiverPostCode(address.getPostCode());

        return orderEntity;
    }

    // 生成订单
    private OrderCreateTo createOrder() {

        OrderCreateTo createTo = new OrderCreateTo();

        //1、生成订单号
        String orderSn = IdWorker.getTimeId();
        OrderEntity orderEntity = builderOrder(orderSn);

        //2、获取到所有的订单项
        List<OrderItemEntity> orderItemEntities = builderOrderItems(orderSn);

        //3、验价(计算价格、积分等信息)
        computePrice(orderEntity,orderItemEntities);

        createTo.setOrder(orderEntity);
        createTo.setOrderItem(orderItemEntities);

        return createTo;
    }

    // 检查价格相关
    private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> itemEntities) {
        BigDecimal total = new BigDecimal("0.0");
        BigDecimal coupon = new BigDecimal("0.0");
        BigDecimal integration = new BigDecimal("0.0");
        BigDecimal promotion = new BigDecimal("0.0");

        //积分、成长值
        Integer integrationTotal = 0;
        Integer growthTotal = 0;

        // 订单的总额，叠加每一个订单项总额信息
        for (OrderItemEntity entity : itemEntities) {
            coupon = coupon.add(entity.getCouponAmount());
            total = total.add(entity.getPromotionAmount());
            integration = integration.add(entity.getIntegrationAmount());
            promotion = promotion.add(entity.getPromotionAmount());

            //积分信息和成长值信息
            integrationTotal += entity.getGiftIntegration();
            growthTotal += entity.getGiftGrowth();
        }
        // 1 订单价格相关
        orderEntity.setTotalAmount(total);
        orderEntity.setCouponAmount(coupon);
        orderEntity.setIntegrationAmount(integration);
        orderEntity.setPromotionAmount(promotion);
        orderEntity.setPayAmount(total.add(orderEntity.getFreightAmount())); // 应付总额

        //设置积分成长值信息
        orderEntity.setIntegration(integrationTotal);
        orderEntity.setGrowth(growthTotal);

        //设置删除状态(0-未删除，1-已删除)
        orderEntity.setDeleteStatus(0);
    }

    // 构建某一个订单项
    private OrderItemEntity buildOrderItem(OrderItemVo cartItem) {
        OrderItemEntity orderItemEntity = new OrderItemEntity();
        // 1. 订单信息：订单号
        Long skuId = cartItem.getSkuId();
        // 2. 商品SPU信息
        R r = productFeign.getSpuInfoByskuId(skuId);
        SpuInfoVo data = r.getData("data",new TypeReference<SpuInfoVo>() {
        });
        orderItemEntity.setSpuId(data.getSpuId());
        orderItemEntity.setSpuBrand(data.getBrandId().toString());
        orderItemEntity.setSpuName(data.getSpuName());
        orderItemEntity.setCategoryId(data.getCatalogId());

        // 3. 商品的sku信息
        orderItemEntity.setSkuId(cartItem.getSkuId());
        orderItemEntity.setSkuName(cartItem.getTitle());
        orderItemEntity.setSkuPic(cartItem.getImage());
        orderItemEntity.setSkuPrice(cartItem.getPrice());

        String sttrAttr = StringUtils.collectionToDelimitedString(cartItem.getSkuAttr(), ";");
        orderItemEntity.setSkuAttrsVals(sttrAttr);

        orderItemEntity.setSkuQuantity(cartItem.getCount());
        // 4. 积分信息
        orderItemEntity.setGiftGrowth(cartItem.getPrice().intValue());
        orderItemEntity.setGiftIntegration(cartItem.getPrice().intValue());

        // 5. 当前订单项的实际金额，总额-各种
        orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity().toString()).
                subtract(orderItemEntity.getPromotionAmount()).
                subtract(orderItemEntity.getIntegrationAmount()).
                subtract(orderItemEntity.getCouponAmount()).
                subtract(orderItemEntity.getRealAmount()));

        return orderItemEntity;
    }

    // 保存订单数据
    private void saveorder(OrderCreateTo order) {
        OrderEntity orderEntity = order.getOrder();
        orderEntity.setCreateTime(new Date());
        orderEntity.setModifyTime(new Date());

        this.baseMapper.insert(orderEntity);

        List<OrderItemEntity> orderItem = order.getOrderItem();
        orderItemService.saveBatch(orderItem);

    }

    /**
     * 构建订单数据
     * @param orderSn
     * @return
     */
    private OrderEntity builderOrder(String orderSn) {

        //获取当前用户登录信息
        MemberResponseVo memberResponseVo = LoginUserInterceptor.login_user.get();

        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setMemberId(memberResponseVo.getId());
        orderEntity.setOrderSn(orderSn);
        orderEntity.setMemberUsername(memberResponseVo.getUsername());

        OrderSubmitVo orderSubmitVo = confirmVoThreadLocal.get();

        //远程获取收货地址和运费信息
        R fareAddressVo = wmsFeign.getFare(orderSubmitVo.getAddrId());
        FareVo fareResp = fareAddressVo.getData("data", new TypeReference<FareVo>() {});

        //获取到运费信息
        BigDecimal fare = fareResp.getFare();
        orderEntity.setFreightAmount(fare);

        //获取到收货地址信息
        MemberAddressVo address = fareResp.getAddress();
        //设置收货人信息
        orderEntity.setReceiverName(address.getName());
        orderEntity.setReceiverPhone(address.getPhone());
        orderEntity.setReceiverPostCode(address.getPostCode());
        orderEntity.setReceiverProvince(address.getProvince());
        orderEntity.setReceiverCity(address.getCity());
        orderEntity.setReceiverRegion(address.getRegion());
        orderEntity.setReceiverDetailAddress(address.getDetailAddress());

        //设置订单相关的状态信息
        orderEntity.setStatus(OrderStatusEnum.CREATE_MEW.getCode());
        //orderEntity.setAutoConfirmDay((Integer)7);
        orderEntity.setConfirmStatus(0);
        return orderEntity;
    }

    /**
     * 构建所有订单项数据
     * @return
     */
    public List<OrderItemEntity> builderOrderItems(String orderSn) {

        List<OrderItemEntity> orderItemEntityList = new ArrayList<>();

        //最后确定每个购物项的价格
        List<OrderItemVo> currentCartItems = cartFeign.getCurrentUserItem();
        if (currentCartItems != null && currentCartItems.size() > 0) {
            orderItemEntityList = currentCartItems.stream().map((items) -> {
                //构建订单项数据
                    OrderItemEntity orderItemEntity = buildOrderItem(items);
                orderItemEntity.setOrderSn(orderSn);

                return orderItemEntity;
            }).collect(Collectors.toList());
        }

        return orderItemEntityList;
    }

}